Ibl exporter#3522
Conversation
Co-authored-by: Garcia Samuel <sam.garcia.die@gmail.com>
…release Prepare minor 0.100.1 release
…ug-fixes Add batch size to KS4 wrapper
for more information, see https://pre-commit.ci
…release Prepare 0.100.2
…_similarity_diff_units Fix template similarity when there are multiple sizes of units
Prepare minor release 0.100.3
Prepare 0.100.4
Preprare 0.100.5
Port bug fix PRs from Main over to 0.100-bug-fixes
Prepare release 0.100.6
for more information, see https://pre-commit.ci
|
This looks like it is off of the bug fixes branch. @jonahpearl you want to switch this to main instead? |
|
I'm not 100% sure what you mean. Do you want me to cherry-pick / rebase my changes onto the main branch? I branched it a while ago so I've had to merge main in a few times. |
|
@jonahpearl thanks for this! Is it ok if I push to this PR? I've been working on refining the export function so I'd be good to be in sync :) |
I think it's correctly using the |
| templates_ind[unit_ind, : len(chan_inds)] = chan_inds | ||
|
|
||
| if not sorting_analyzer.has_extension("template_similarity"): | ||
| if sorting_analyzer.get_extension("template_similarity") is None: |
There was a problem hiding this comment.
You're suggesting we put this back to "has_extension"? Any reason this one and not the other ones? The ibl export relies on doing a Phy export, and as discussed elsewhere this "has_extension" pattern is no longer safe if the folder exists but without any data inside.
There was a problem hiding this comment.
yes, all of them. I think it's much easier to read :)
There was a problem hiding this comment.
I agree that it'd be easier to read, but I disagree that it's preferable, because it will break if the extension folder exists but doesn't have data. It's not unusual to end up in that kind of state — eg if you run analyzer.compute(["random_spikes", "spike_amplitudes"]) on a new analyzer, the spike_amplitudes folder will get made but nothing will be in it because the analyzer will need "templates" to be computed. There are various ways to fix that involving try/excepts / clean-ups, but in the current context, I don't think it makes sense to not catch this case.
There was a problem hiding this comment.
That's a separate issue :) we should delay folder creation until dependencies are checked. Can you open another issue about it?
| from spikeinterface.core import extract_waveforms | ||
| from spikeinterface.extractors import toy_example | ||
| from spikeinterface.comparison import compare_templates | ||
|
|
||
| import numpy as np |
There was a problem hiding this comment.
Yes, not sure how this slipped in.
|
|
||
| import numpy as np | ||
| import numpy.typing as npt | ||
| from scipy.signal import welch |
There was a problem hiding this comment.
import scipy should be done within the functions using it because it's not a mandatory requirement (see failing tests)
Co-authored-by: Alessio Buccino <alejoe9187@gmail.com>
for more information, see https://pre-commit.ci
zm711
left a comment
There was a problem hiding this comment.
Just a docstring fix while you're at it. I believe we add this to the dev docs after this PR was started which is why this was missed.
| ---------- | ||
| analyzer: SortingAnalyzer | ||
| The sorting analyzer object. | ||
| output_folder: str | Path | ||
| The output folder where the phy template-gui files are saved | ||
| rms_win_length_sec: float, default: 3 | ||
| The window length in seconds for the RMS calculation. | ||
| welch_win_length_samples: int, default: 1024 | ||
| The window length in samples for the Welch method. | ||
| total_secs: int, default: 100 | ||
| The total number of seconds to use for the spectral density calculation. | ||
| only_ibl_specific_steps: bool, default: False | ||
| If True, only the IBL specific steps are run (i.e. skips calling `export_to_phy`) | ||
| compute_pc_features: bool, default: False | ||
| If True, pc features are computed | ||
| compute_amplitudes: bool, default: True | ||
| If True, waveforms amplitudes are computed | ||
| sparsity: ChannelSparsity or None, default: None | ||
| The sparsity object (currently only respected for phy part of the export) | ||
| copy_binary: bool, default: True | ||
| If True, the recording is copied and saved in the phy "output_folder" | ||
| remove_if_exists: bool, default: False | ||
| If True and "output_folder" exists, it is removed and overwritten | ||
| template_mode: str, default: "median" | ||
| Parameter "mode" to be given to WaveformExtractor.get_template() | ||
| dtype: dtype or None, default: None | ||
| Dtype to save binary data | ||
| verbose: bool, default: True | ||
| If True, output is verbose | ||
| use_relative_path : bool, default: False | ||
| If True and `copy_binary=True` saves the binary file `dat_path` in the `params.py` relative to `output_folder` (ie `dat_path=r"recording.dat"`). If `copy_binary=False`, then uses a path relative to the `output_folder` | ||
| If False, uses an absolute path in the `params.py` (ie `dat_path=r"path/to/the/recording.dat"`) |
There was a problem hiding this comment.
| ---------- | |
| analyzer: SortingAnalyzer | |
| The sorting analyzer object. | |
| output_folder: str | Path | |
| The output folder where the phy template-gui files are saved | |
| rms_win_length_sec: float, default: 3 | |
| The window length in seconds for the RMS calculation. | |
| welch_win_length_samples: int, default: 1024 | |
| The window length in samples for the Welch method. | |
| total_secs: int, default: 100 | |
| The total number of seconds to use for the spectral density calculation. | |
| only_ibl_specific_steps: bool, default: False | |
| If True, only the IBL specific steps are run (i.e. skips calling `export_to_phy`) | |
| compute_pc_features: bool, default: False | |
| If True, pc features are computed | |
| compute_amplitudes: bool, default: True | |
| If True, waveforms amplitudes are computed | |
| sparsity: ChannelSparsity or None, default: None | |
| The sparsity object (currently only respected for phy part of the export) | |
| copy_binary: bool, default: True | |
| If True, the recording is copied and saved in the phy "output_folder" | |
| remove_if_exists: bool, default: False | |
| If True and "output_folder" exists, it is removed and overwritten | |
| template_mode: str, default: "median" | |
| Parameter "mode" to be given to WaveformExtractor.get_template() | |
| dtype: dtype or None, default: None | |
| Dtype to save binary data | |
| verbose: bool, default: True | |
| If True, output is verbose | |
| use_relative_path : bool, default: False | |
| If True and `copy_binary=True` saves the binary file `dat_path` in the `params.py` relative to `output_folder` (ie `dat_path=r"recording.dat"`). If `copy_binary=False`, then uses a path relative to the `output_folder` | |
| If False, uses an absolute path in the `params.py` (ie `dat_path=r"path/to/the/recording.dat"`) | |
| ---------- | |
| analyzer : SortingAnalyzer | |
| The sorting analyzer object. | |
| output_folder : str | Path | |
| The output folder where the phy template-gui files are saved | |
| rms_win_length_sec : float, default: 3 | |
| The window length in seconds for the RMS calculation. | |
| welch_win_length_samples : int, default: 1024 | |
| The window length in samples for the Welch method. | |
| total_secs : int, default: 100 | |
| The total number of seconds to use for the spectral density calculation. | |
| only_ibl_specific_steps : bool, default: False | |
| If True, only the IBL specific steps are run (i.e. skips calling `export_to_phy`) | |
| compute_pc_features : bool, default: False | |
| If True, pc features are computed | |
| compute_amplitudes : bool, default: True | |
| If True, waveforms amplitudes are computed | |
| sparsity : ChannelSparsity or None, default: None | |
| The sparsity object (currently only respected for phy part of the export) | |
| copy_binary : bool, default: True | |
| If True, the recording is copied and saved in the phy "output_folder" | |
| remove_if_exists : bool, default: False | |
| If True and "output_folder" exists, it is removed and overwritten | |
| template_mode : str, default: "median" | |
| Parameter "mode" to be given to WaveformExtractor.get_template() | |
| dtype : dtype or None, default: None | |
| Dtype to save binary data | |
| verbose : bool, default: True | |
| If True, output is verbose | |
| use_relative_path : bool, default: False | |
| If True and `copy_binary=True` saves the binary file `dat_path` in the `params.py` relative to `output_folder` (ie `dat_path=r"recording.dat"`). If `copy_binary=False`, then uses a path relative to the `output_folder` | |
| If False, uses an absolute path in the `params.py` (ie `dat_path=r"path/to/the/recording.dat"`) |
We are working on implementing numpydoc linting in the future and it requires there to be a space after the parameter.
| try: | ||
| from scipy.signal import welch | ||
| except ImportError as e: | ||
| raise ImportError("Please install scipy to use the export_to_ibl function.") from e |
There was a problem hiding this comment.
I've never seen this before. How does this raise error from e work?
There was a problem hiding this comment.
I would just import it in the function. The problem is that core tests will look in all files for tests, and script is not installed in core tests
| "fscale": fscale(welch_win_length_samples, 1 / fs_ap, one_sided=True), | ||
| "tscale": wingen.tscale(fs=fs_ap), | ||
| } | ||
| win["spectral_density"] = np.zeros((len(win["fscale"]), analyzer.recording.get_num_channels())) |
There was a problem hiding this comment.
I think we should have a proper function to compute the spectrum if you need it.
So we could have proper tests for this.
| total_samples_ap = int(np.min([fs_ap * total_secs, analyzer.recording.get_num_samples()])) | ||
|
|
||
| # the window generator will generates window indices | ||
| wingen = WindowGenerator(ns=total_samples_ap, nswin=rms_win_length_samples_ap, overlap=0) |
There was a problem hiding this comment.
we have already some function to generate window in spikeinterface.
|
Hi @jonahpearl About About the spectrum, I would implement it in a speparate file using the spikeinterface machinery on chunk parralelisation. |
|
Fair enough -- I don't have time to refactor this right now but I can work on it in the coming months. |
|
Closing in favor of newer version |
|
Function for #2843
Would be great if a few others could test on their data. Thanks!